<template>
  <el-popover :popper-class="props.class" :effect="props.effect"
              :placement="props.placement" :disabled="props.disabled"
              :show-arrow="!props.noShowArrow" :offset="offsetD"
              :show-after="showTimeD" :hide-after="hideTimeD"
              :visible="visibleD" @show="showFn" @hide="hideFn"
              :popper-style="props.style" :teleported="!props.noBody"
              :trigger="triggerD" :width="props.width">
    <template #reference>
        <span class="titleBox" ref="titleDom" @click="closeFn" :class="props.titleClass">
          <slot :visible="visibleD" :trigger="triggerD">
            <span class="titleText">{{ props.title }}</span>
          </slot>
        </span>
    </template>

    <!-- 内容区 -->
    <div class="popoverXContent" :class="props.contentClass" :style="props.contentStyle">
      <slot name="content" :visible="visibleD" :trigger="triggerD">
        <span class="contentText">{{ props.content }}</span>
      </slot>
    </div>
  </el-popover>
</template>

<script setup>
import {ref, watch} from 'vue'
import { ElPopover } from 'element-plus'

const props = defineProps({
  // 标题
  title: {
    type: String,
    default: "props.title"
  },
  // 标题类名
  titleClass: {
    type: [String, Object],
    default: "titleClass"
  },

  // 内容
  content: {
    type: String,
    default: ""
  },
  // 内容类名
  contentClass: {
    type: [String, Object],
    default: "contentClass"
  },

  /* 组件属性 */
  // 宽度
  width: {
    type: [String, Number],
    default: "auto"
  },

  // 弹窗类名
  class: {
    type: [String, Object],
    default: "xhPopover"
  },

  // 弹窗样式
  style: {
    type: [String, Object],
    default: ""
  },

  // 内容样式
  contentStyle: {
    type: [String, Object],
    default: ""
  },

  // 弹窗方式：click/focus/hover/contextmenu。
  // 除了常规的还有自定义的：clickHover(点击打开，再点击或移出时隐藏)
  trigger: {
    type: String,
    default: 'clickHover'
  },

  // 主题
  effect: {
    type: String,
    default: "light"
  },

  // 出现的位置。top/top-start/top-end/bottom/bottom-start/bottom-end/left/left-start/left-end/right/right-start/right-end
  placement: {
    type: String,
    default: "top"
  },

  // 禁止
  disabled: {
    type: Boolean,
    default: false
  },

  // 不显示箭头
  noShowArrow: {
    type: Boolean,
    default: false
  },

  // 偏移量
  offset: {
    type: [Number, String],
    default: 10
  },

  // 多久显示
  showTime: {
    type: [Number, String],
    default: 0
  },

  // 多久隐藏
  hideTime: {
    type: [Number, String],
    default: 200
  },

  // 显示
  visible: {
    type: [Boolean, undefined],
    default: undefined
  },

  // 到body
  noBody: {
    type: Boolean,
    default: false
  },

})

// 函数方法
// 判断列表里面是否包含对象。字符串时是否转为小写再比较
const includesList = (list, obj, toLower = true) => {
  let result = false
  list.find(row => {
    let tempObj = obj
    let value = row;
    if (toLower) {
      if (typeof tempObj == 'string') {
        tempObj = obj.toLowerCase()
      }
      if (typeof value == 'string') {
        value = row.toLowerCase()
      }
    }
    if (value == tempObj) {
      result = true
      return true
    }
  })
  return result
}


const emit = defineEmits(['update:visible', 'show', 'hide'])


// 偏移量
const offsetD = ref(10)
watch(() => props.offset, newV => {
  offsetD.value = parseFloat(newV)
}, {immediate: true, deep: true})

// 多久显示
const showTimeD = ref(0)
watch(() => props.showTime, newV => {
  showTimeD.value = parseFloat(newV)
}, {immediate: true, deep: true})

// 多久隐藏
const hideTimeD = ref(0)
watch(() => props.hideTime, newV => {
  hideTimeD.value = parseFloat(newV)
}, {immediate: true, deep: true})


/* 自定义弹窗方式 */
// 弹窗方式
// 自定义显示列表
let triggerList = ref(['clickHover'])
// 原先方式
let haveList = ref(["click", "focus", "hover", "contextmenu"])
const triggerD = ref(undefined)

// 判断是否为原有方式
const getTrigger = () => {
  // 判断是否为自定义方式
  if (includesList(triggerList.value, props.trigger)) {
    switch (props.trigger.toLowerCase()) {
      // clickHover(点击打开，再点击或移出时隐藏)
      case 'clickhover':
        triggerD.value = "click";
        break;

    }
  } else {
    // 非原先有的则默认点击
    if (includesList(haveList.value, props.trigger)) {
      triggerD.value = props.trigger
    } else {
      triggerD.value = 'click'
    }
  }
}

watch(() => props.trigger, newV => {
  getTrigger()
}, {deep: true, immediate: true})

// 显示对象
const visibleD = ref(undefined)
watch(() => props.visible, newV => {
  visibleD.value = newV
}, {immediate: true, deep: true})


/* 事件 */
// 显示回调
const showFn = () => {
  // 如果是自定义类型
  if (includesList(triggerList.value, props.trigger)) {
    switch (props.trigger.toLowerCase()) {
      // clickHover(点击打开，再点击或移出时隐藏)
      case 'clickhover':
        triggerD.value = "hover";
        break;
    }
  }
  emit("show")
}

// 隐藏回调
const hideFn = () => {
  // 如果是自定义类型
  if (includesList(triggerList.value, props.trigger)) {
    switch (props.trigger.toLowerCase()) {
      // clickHover(点击打开，再点击或移出时隐藏)
      case 'clickhover':
        triggerD.value = "click";
        break;
    }
  }

  emit('hide')
}

// 点击标题
const closeFn = () => {
  // 如果是自定义类型
  if (includesList(triggerList.value, props.trigger)) {
    switch (props.trigger.toLowerCase()) {
      // clickHover(点击打开，再点击或移出时隐藏)
      case 'clickhover':
        if (triggerD.value == 'hover') {
          triggerD.value = 'click'
        }
        break;
    }
  }
}


/* 外部方法 */
// 关闭弹窗
const closePopover = () => {
  visibleD.value = false
  getTrigger()
  setTimeout(() => {
    visibleD.value = props.visible
  }, 200)
}


const titleDom = ref({})

defineExpose({
  close: closePopover,
  show: () => {
    titleDom.value.click()
  }
})

</script>

<style scoped lang='scss'>
.popoverX {
  display: inline-block;
  height: 100%;
  width: 100%;
}

.titleBox {
  width: auto;
  height: auto;
}


// 标题样式
.titleClass {
}

// 内容样式
.contentClass {
  height: 100%;
  width: 100%;
}

.popoverXContent {
}

</style>